package com.esun.service.component;

import com.alibaba.fastjson.JSONObject;
import com.esun.dao.das.DatabaseLogDas;
import com.esun.dao.das.OperationLogDas;
import com.esun.dao.eo.DatabaseLogEo;
import com.esun.dao.eo.OperationLogEo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.PeriodicTrigger;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * 日志定时器
 *
 * @author John.xiao
 * @date 2021/10/13 10:25
 */
@Component
@EnableScheduling
@Slf4j
@ConditionalOnExpression("${esun.log.retry.enable:true}")
public class LogSchedule implements SchedulingConfigurer {

	@Resource
	DatabaseLogDas databaseLogDas;
	@Resource
	OperationLogDas operationLogDas;
	@Resource
	DatabaseLogComponent databaseLogComponent;
	@Resource
	OperationLogComponent operationLogComponent;
	@Value("${spring.application.name}")
	private String service;
	@Value("${esun.log.retry.interval:60000}")
	private Long interval;
	@Value("${esun.log.retry.times:3}")
	private Integer maxRetryTimes;
	
	@Override
	public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
		scheduledTaskRegistrar.addTriggerTask(() -> {
			retryDataBaseLog();
			retryOperationLog();
		}, triggerContext -> {
			PeriodicTrigger periodicTrigger = new PeriodicTrigger(interval);
			return periodicTrigger.nextExecutionTime(triggerContext);
		});
	}

	public void retryDataBaseLog() {
		Map<Long, RetryEntity> databaseLogs = databaseLogComponent.getErrorLogs();
		for (Map.Entry<Long, RetryEntity> entry : databaseLogs.entrySet()) {
			Long key = entry.getKey();
			String message = entry.getValue().getMessage();
			int retryTimes = entry.getValue().getRetryTimes();

			try {
				DatabaseLogEo databaseLog = JSONObject.parseObject(message, DatabaseLogEo.class);
				databaseLogDas.insert(databaseLog);
				databaseLogComponent.remove(key);
			} catch (Exception e) {
				if (retryTimes > maxRetryTimes){
					createErrorLog(message, e);
					databaseLogComponent.remove(key);
				}
				else {
					entry.getValue().setRetryTimes(retryTimes +1);
				}
			}
		}
	}

	public void retryOperationLog() {
		Map<Long, RetryEntity> operationLogs = operationLogComponent.getErrorLogs();
		for (Map.Entry<Long, RetryEntity> entry : operationLogs.entrySet()) {
			Long key = entry.getKey();
			String message = entry.getValue().getMessage();
			int retryTimes = entry.getValue().getRetryTimes();
			try {
				OperationLogEo databaseLog = JSONObject.parseObject(message, OperationLogEo.class);
				operationLogDas.insert(databaseLog);
				operationLogComponent.remove(key);
			} catch (Exception e) {
				if (retryTimes > maxRetryTimes){
					createErrorLog(message, e);
					operationLogComponent.remove(key);
				}
				else {
					entry.getValue().setRetryTimes(retryTimes +1);
				}
			}
		}
	}

	public void createErrorLog(String message, Exception e) {
		String module = "operationLog";
		int errorStatus = 1;
		OperationLogEo operationLogEo = OperationLogEo.builder()
				.service(service)
				.module(module)
				.status(errorStatus)
				.exception(e.getMessage())
				.message(message)
				.createDatetime(LocalDateTime.now())
				.build();
		operationLogDas.insert(operationLogEo);
	}


}
